package com.xcm.controller.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.xcm.constant.ClientConstant;
import com.xcm.constant.PollConfigType;
import com.xcm.core.annotation.ClientPermissionRequired;
import com.xcm.model.OperationResult;
import com.xcm.model.Tag;
import com.xcm.model.TbDeviceInfo;
import com.xcm.model.TbDeviceUpgrade;
import com.xcm.model.TbMachine;
import com.xcm.model.TbPollConfig;
import com.xcm.model.TbProgramBottom;
import com.xcm.model.TbProgramInfo;
import com.xcm.model.TbProgramJson;
import com.xcm.model.TbProgramTag;
import com.xcm.model.TbProgramTop;
import com.xcm.model.bo.ClientDeviceBO;
import com.xcm.model.dto.NewestProgramDTO;
import com.xcm.service.ClientService;
import com.xcm.service.DeviceInfoService;
import com.xcm.service.DeviceUpgradeService;
import com.xcm.service.PollConfigService;
import com.xcm.service.ProgramBottomService;
import com.xcm.service.ProgramInfoService;
import com.xcm.service.ProgramJsonService;
import com.xcm.service.ProgramTagService;
import com.xcm.service.ProgramTopService;
import com.xcm.util.DateTools;
import com.xcm.util.HttpUtils;

/**
 * 
 * <p>Title: ClientContoller</p>  
 * <p>Description: 客户端主动发起请求与服务端进行数据交互</p>  
 * @author huangf 
 * @date 2018年4月19日
 */
@Controller
@ClientPermissionRequired
@RequestMapping(value = "/client")
public class ClientContoller {
	private static Logger logger = LoggerFactory.getLogger(ClientContoller.class);
	@Autowired
	private DeviceInfoService deviceInfoService;
	@Autowired
	private ClientService clientService;
	@Autowired
	private PollConfigService pollConfigService;
	@Autowired
	private ProgramInfoService programInfoService;
	@Autowired
	private ProgramTopService programTopService;
	@Autowired
	private ProgramBottomService programBottomService;
	@Autowired
	private ProgramJsonService programJsonService;
	@Autowired
	private DeviceUpgradeService deviceUpgradeService;
	@Autowired
	private ProgramTagService programTagService;
	/**
	 * 此接口会做很多事情，终端会轮询调用服务端。服务端返回相应的操作指令
	 * callType @see PollConfigType 服务端返回轮询时需要带入的参数内容。终端每次带上类型。减少服务器二次查询开支 
	 * callReport  ： 上报终端信息
	 * callConfig  ： 获取最新的轮询配置
	 * callState   ： 获取最新的状态及设置信息
	 * callUpgrade ： 获取最新升级信息
	 */
	@ResponseBody
	@RequestMapping(value = "/call",method =RequestMethod.POST) 
	public Object report(String callType,@RequestHeader("AppVersion") String deviceSoftVer , @RequestHeader("VersionCode") String VersionCode,@RequestHeader("deviceId") String deviceNum, @RequestHeader("mac") String deviceMac,
			@RequestHeader("deviceModel") String deviceModel, HttpServletRequest request,String deviceResolution,String deviceCoordinate,
			String deviceHardVer,String deviceSysVer,String deviceDiskSpace,Long bootTime,String xcVersion) {
		Map<String,Object> map = new HashMap<>();
		OperationResult<Map<String,Object>> result = new OperationResult<Map<String,Object>>(ClientConstant.CODE_SUCCESS, ClientConstant.MSG_SUCCESS, map);
			
		// callConfig {callType 为空时，默认操作为获取配置信息}
		if ( StringUtils.isBlank(callType) || callType.contains(PollConfigType.config.name()) ) {
			List<TbPollConfig> callConfig = callConfig();
			map.put(PollConfigType.config.name(), callConfig);
		}
		
		// 减少数据库查询压力
		TbDeviceInfo currentDeviceInDB = deviceInfoService.getDeviceInfoByMac(deviceMac);
		
		// callReport
		if ( StringUtils.isNotBlank(callType) && callType.contains(PollConfigType.report.name()) ) {
			TbDeviceInfo deviceInfoReport = new TbDeviceInfo(deviceNum, deviceCoordinate, deviceResolution, deviceMac, deviceSoftVer, deviceHardVer, deviceSysVer, deviceModel, deviceDiskSpace);
			OperationResult<Object> callReport = callReport(deviceInfoReport,currentDeviceInDB,request,bootTime);
			map.put(PollConfigType.report.name(), callReport);
		}
		
		// callState
		if ( StringUtils.isNotBlank(callType) && callType.contains(PollConfigType.state.name()) ) {
			OperationResult<Object> callState = callState( deviceMac,  xcVersion, currentDeviceInDB);
			map.put(PollConfigType.state.name(), callState);
		}
		
		// callUpgrade
		if ( StringUtils.isNotBlank(callType) && callType.contains(PollConfigType.upgrade.name()) ) {
			OperationResult<Object> callUpgrade = callUpgrade(deviceHardVer, deviceMac, deviceSoftVer,VersionCode,currentDeviceInDB);
			map.put(PollConfigType.upgrade.name(), callUpgrade);
		}
		return result;
	}
	
	private OperationResult<Object> callReport(TbDeviceInfo reportDeviceInfo,TbDeviceInfo currentDeviceInDB,HttpServletRequest request, Long bootTime) {
		// 校验终端上传数据是否合法
		OperationResult<Object> checker = new OperationResult<>();
		checkParam(checker, reportDeviceInfo);
		if ( ClientConstant.CODE_SUCCESS != checker.getCode() ) {
			return checker;
		}
		try {
			Long now = System.currentTimeMillis();
			if ( bootTime == null ) {
				bootTime = now;
			}
			if (currentDeviceInDB == null) {
				// 如果终端信息不存在，新增终端信息
				reportDeviceInfo.setDeviceIp(HttpUtils.getRemortIP(request));	//获取ip地址和位置信息
				reportDeviceInfo.setDeviceStatus(0);
				reportDeviceInfo.setReportTime(now);
				reportDeviceInfo.setOnlineTime(now-bootTime);
				reportDeviceInfo.setOnlineTimeTotal(now-bootTime);
				reportDeviceInfo.setAddTime(now);
				TbMachine machine = deviceInfoService.getMachineByMachineNum(reportDeviceInfo.getDeviceNum());
				if ( machine != null ) {
					reportDeviceInfo.setDeviceProvince(machine.getProvince());
					reportDeviceInfo.setDeviceCity(machine.getCity());
					reportDeviceInfo.setDeviceCounty(machine.getDistrict());
				}
				deviceInfoService.saveDeviceInfo(reportDeviceInfo);
			} else {
				// 如果终端信息存在，更新终端信息
				currentDeviceInDB.setDeviceIp(HttpUtils.getRemortIP(request));
				currentDeviceInDB.setDeviceStatus(0);
				currentDeviceInDB.setReportTime(now);
				currentDeviceInDB.setOnlineTime(now-bootTime);
				currentDeviceInDB.setOnlineTimeTotal(currentDeviceInDB.getOnlineTimeTotal() + (now-bootTime));
				currentDeviceInDB.setDeviceNum(reportDeviceInfo.getDeviceNum());
				currentDeviceInDB.setDeviceSoftVer(reportDeviceInfo.getDeviceSoftVer());
				currentDeviceInDB.setDeviceModel(reportDeviceInfo.getDeviceModel());
				currentDeviceInDB.setDeviceResolution(reportDeviceInfo.getDeviceResolution());
				currentDeviceInDB.setDeviceCoordinate(reportDeviceInfo.getDeviceCoordinate());
				currentDeviceInDB.setDeviceHardVer(reportDeviceInfo.getDeviceHardVer());
				currentDeviceInDB.setDeviceSysVer(reportDeviceInfo.getDeviceSysVer());
				currentDeviceInDB.setDeviceDiskSpace(reportDeviceInfo.getDeviceDiskSpace());
				deviceInfoService.updateDeviceInfo(currentDeviceInDB);
			}
			return new OperationResult<>(ClientConstant.CODE_SUCCESS, "上报数据成功");
		} catch (Exception e) {
			logger.error("ClientContoller callReport 上报终端数据失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}
	
	private List<TbPollConfig> callConfig() {
		return pollConfigService.getAllPollConfig();
	}
	
	private OperationResult<Object> callState(String deviceMac, String xcVersion,TbDeviceInfo currentDeviceInDB) {
		if (currentDeviceInDB == null) {
			return new OperationResult<>(ClientConstant.CODE_DEVICE_NOT_FOUND, ClientConstant.MSG_DEVICE_NOT_FOUND);
		}
		try {
			ClientDeviceBO states = clientService.getStates(deviceMac, xcVersion,currentDeviceInDB);
			return new OperationResult<>(ClientConstant.CODE_SUCCESS, "获取设置数据成功",states);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("ClientContoller callState 获取最新设置数据失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}
	
	private OperationResult<Object> callUpgrade(String deviceHardVer, String deviceMac, String deviceSoftVersion, String versionCode,TbDeviceInfo currentDeviceInDB) {
		if (currentDeviceInDB == null) {
			return new OperationResult<>(ClientConstant.CODE_DEVICE_NOT_FOUND, ClientConstant.MSG_DEVICE_NOT_FOUND);
		}
		if (StringUtils.isBlank(deviceHardVer)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "deviceHardVer不能为空");
		}
		if (StringUtils.isBlank(deviceSoftVersion)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "deviceSoftVersion不能为空");
		}
		if (StringUtils.isBlank(versionCode)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "versionCode不能为空");
		}
		try {
			
			// 记录升级信息
			List<TbDeviceUpgrade> upgrades = new ArrayList<>();
			boolean upedFlag = false;// 终端上传的软件、固件版本号与升级信息的软件、固件号做对比。如果一致，则代表终端以升级成功。将终端表的升级id置为null
			// 获取终端apk升级信息
			if ( currentDeviceInDB.getSoftwareUpgradeId() != null ) {
				TbDeviceUpgrade softwareUpgrade = deviceUpgradeService.getDeviceUpgradeById(currentDeviceInDB.getSoftwareUpgradeId());
				if (softwareUpgrade != null && Integer.valueOf(versionCode).intValue() < softwareUpgrade.getVersionCode().intValue() ) {
					upgrades.add(softwareUpgrade);
				}else if (softwareUpgrade != null && Integer.valueOf(versionCode).intValue() == softwareUpgrade.getVersionCode().intValue()){
					// 当升级版本信息与终端上报版本信息一致时代表已升级成功，更新数据库
					upedFlag = true;
					currentDeviceInDB.setSoftwareUpgradeId(null);
				}
			}
			
			// 获取终端固件升级信息
			if ( currentDeviceInDB.getFirmwareUpgradeId() != null ) {
				TbDeviceUpgrade firewareUpgrade = deviceUpgradeService.getDeviceUpgradeById(currentDeviceInDB.getFirmwareUpgradeId());
				if (firewareUpgrade != null && !firewareUpgrade.getVersionName().equals(deviceHardVer)) {
					upgrades.add(firewareUpgrade);
				} else if (firewareUpgrade != null && firewareUpgrade.getVersionName().equals(deviceHardVer)){
					// 当升级版本信息与终端上报版本信息一致时代表已升级成功，更新数据库
					upedFlag = true;
					currentDeviceInDB.setFirmwareUpgradeId(null);
				}
			}
			
			if ( upedFlag ) {
				deviceInfoService.updateDeviceInfo(currentDeviceInDB);
			}
			return new OperationResult<>( ClientConstant.CODE_SUCCESS, "获取更新信息成功",upgrades);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("ClientContoller getUpdateApk 获取升级信息失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}
	
	/**
	 * 获取最新广告数据
	 */
	@ResponseBody
	@RequestMapping(value = "getNewestProgram",method =RequestMethod.POST)
	public Object getNewestProgram(@RequestHeader("deviceId") String deviceNum, String xcVersion) {
		
		//验证xcVersion是否为空
		if (StringUtils.isBlank(xcVersion)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "xcVersion不能为空");
		}
		
		try {
			// 通过机器码查询节目信息
			NewestProgramDTO newestProgramDTO = new NewestProgramDTO();
			TbProgramInfo programInfo = programInfoService.getProgramInfoByMachineNum(deviceNum,xcVersion);
			if ( programInfo != null ) {
				//下屏节目列表
				List<TbProgramTag> programTags = null;
				List<TbProgramBottom> bottomList = programBottomService.listProgramBottomByXcVersion(programInfo.getXcVersion(), programInfo.getBottom());
				if ( bottomList !=null ) {
					programTags = programTagService.findByXcVersion(null);
					if ( CollectionUtils.isNotEmpty(programTags) ) {
						setBottomTag(bottomList,programTags);
					}
				}
				//上屏节目列表
				List<TbProgramTop> topList = programTopService.listProgramTopByXcVersion(programInfo.getXcVersion(), programInfo.getTop());
				if ( bottomList !=null ) {
					if ( CollectionUtils.isNotEmpty(programTags) ) {
						setTopTag(topList,programTags);
					}
				}
				
				//获取JsonName
				TbProgramJson programJson = programJsonService.getProgramJsonByXcVersion(programInfo.getXcVersion());
				newestProgramDTO.setXcVersion(xcVersion);
				newestProgramDTO.setJsonName(programJson.getName());
				newestProgramDTO.setTopProgramList(topList);
				newestProgramDTO.setBottomProgramList(bottomList);
			}
			return new OperationResult<>( ClientConstant.CODE_SUCCESS, "获取最新节目信息成功",newestProgramDTO);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("ClientContoller getNewestProgram 获取最新节目信息失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}
	
	/**
	 * 上报广告数据的下载状态
	 */
	@ResponseBody
	@RequestMapping(value = "uploadDownloadStatus",method =RequestMethod.POST)
	public Object setDownload(HttpServletRequest request,@RequestHeader("mac") String deviceMac, String playJson, String downloadJson, Integer state, String failureReasonon) {
		
		if (StringUtils.isBlank(downloadJson)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "downloadJson不能为空");
		}
		if (StringUtils.isBlank(deviceMac)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "mac不能为空");
		}
		if ( state == null ) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "state不能为空");
		}
		try {
			clientService.setDownload(deviceMac, playJson, downloadJson, state,failureReasonon,HttpUtils.getRemortIP(request));
			return new OperationResult<>(ClientConstant.CODE_SUCCESS, "上报成功");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("ClientContoller setDownload 上报广告数据的下载状态失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}

	/**
	 * 上传终端日志
	 */
	@ResponseBody
	@RequestMapping(value = "uploadLog",method =RequestMethod.POST)
	public Object uploadLog(@RequestHeader("mac") String deviceMac, String url,String type) {
		//验证参数是否为空
		if (StringUtils.isBlank(url)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "url不能为空");
		}
		if (url.length() > 256) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_ILLEGAL, "url格式不正确");
		}
		if (StringUtils.isBlank(deviceMac)) {
			return new OperationResult<>(ClientConstant.CODE_PARAM_MISSING, "mac不能为空");
		}
		try {
			StringBuilder name = new StringBuilder(deviceMac).append("_").append(DateTools.dateToString(new Date(), DateTools.DATE_PATTERN_NUMBER));
			clientService.uploadLog(deviceMac, name.toString(), url,type);
			return new OperationResult<>(ClientConstant.CODE_SUCCESS, "上传成功");
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("ClientContoller uploadLog 上传终端日志失败：" + e.getMessage());
			return OperationResult.newSystemErrorOperationResult();
		}
	}

	private OperationResult<Object> checkParam(OperationResult<Object> checker,TbDeviceInfo deviceInfo) {
		
		if ( StringUtils.isBlank(deviceInfo.getDeviceNum()) ) {
			checker.setMsg("终端机器码参数缺失");
			checker.setCode(ClientConstant.CODE_PARAM_MISSING);
			return checker;
		}
		if ( deviceInfo.getDeviceNum().length() > 50 ) {
			checker.setMsg("终端机器码格式不正确");
			checker.setCode(ClientConstant.CODE_PARAM_ILLEGAL);
			return checker;
		}
		if ( StringUtils.isBlank(deviceInfo.getDeviceMac()) ) {
			checker.setMsg("终端MAC参数缺失");
			checker.setCode(ClientConstant.CODE_PARAM_MISSING);
			return checker;
		}
		if ( StringUtils.isBlank(deviceInfo.getDeviceSoftVer()) ) {
			checker.setMsg("终端软件版本参数缺失");
			checker.setCode(ClientConstant.CODE_PARAM_MISSING);
			return checker;
		}
		if ( deviceInfo.getDeviceSoftVer().length() > 64 ) {
			checker.setMsg("终端软件版本号格式不正确");
			checker.setCode(ClientConstant.CODE_PARAM_ILLEGAL);
			return checker;
		}
		if ( StringUtils.isBlank(deviceInfo.getDeviceModel()) ) {
			checker.setMsg("终端型号参数缺失");
			checker.setCode(ClientConstant.CODE_PARAM_MISSING);
			return checker;
		}
		if ( deviceInfo.getDeviceModel().length() > 64 ) {
			checker.setMsg("终端型号格式不正确");
			checker.setCode(ClientConstant.CODE_PARAM_ILLEGAL);
			return checker;
		}
		checker.setCode(ClientConstant.CODE_SUCCESS);
		return checker;
	}
	
	private void setTopTag(List<TbProgramTop> tops, List<TbProgramTag> programTags) {
		List<Tag> tags = null;
		for ( TbProgramTop top : tops ) {
			tags = new ArrayList<>();
			for ( TbProgramTag tag :  programTags ) {
				if ( tag!=null && top!=null) {
					if (top.getName().equals(tag.getProgramName())) {
						tags.add(new Tag(tag.getTagId(),tag.getTagContent(),tag.getTagContent()));
					}
				}	
			}
			top.setTags(tags);
		}
	}

	private void setBottomTag(List<TbProgramBottom> bottoms, List<TbProgramTag> programTags) {
		List<Tag> tags = null;
		for ( TbProgramBottom bottom : bottoms ) {
			tags = new ArrayList<>();
			for ( TbProgramTag tag :  programTags ) {
				if ( tag!=null && bottom!=null) {
					if (bottom.getName().equals(tag.getProgramName())) {
						tags.add(new Tag(tag.getTagId(),tag.getTagContent(),tag.getTagContent()));
					}
				}
			}
			bottom.setTags(tags);
		}
	}
}
